iceoryx2 发布订阅上手:节点、服务与零拷贝收发
本文翻译整理自 The iceoryx2 Book 的 Getting Started — A Robot Nervous System — Publish–Subscribe 一章,代码与叙述以官方文档为准。适合第一次接触 iceoryx2、想跑通第一个发布订阅示例的开发者;读完可以得到从创建节点到零拷贝收发消息的完整代码路径。iceoryx2 的分层架构与四种通信模型的概览,可以先阅读 book 的 concepts 章节。
一切从节点开始
在 iceoryx2 中,一切皆以节点开始。节点代表一个通信点(如进程或线程),并充当服务的工厂。为了在调试时保持条理清晰,给这个节点命名:
#include "iceoryx2.hpp"
using namespace iox2;
auto node = NodeBuilder()
.name(NodeName::create("UltraSonicSensor").value())
.create<ServiceType::Ipc>().value(); 定义负载结构体
现在我们可以创建一个名为 "distance_to_obstacle" 的服务,使用 Distance 结构体作为有效载荷类型。有效载荷必须是共享内存兼容的,这意味着:
- self contained,自包含的
- no internal pointers,无内部指针
- identical memory representation,相同的内存表示
struct Distance {
double distance_in_meters;
float some_other_property;
};
inline auto operator<<(std::ostream& stream, const Distance& value) -> std::ostream& {
stream << "Distance { distance_in_meters: " << value.distance_in_meters
<< ", some_other_property: " << value.some_other_property << " }";
return stream;
} 创建服务与发布者
在定义了有效载荷后,我们可以设置该服务:
auto service = node.service_builder(ServiceName::create("distance_to_obstacle").value())
.publish_subscribe<Distance>()
.open_or_create()
.value(); 现在我们创建我们的发布者:
auto publisher = service.publisher_builder().create().value(); 要充分利用零拷贝,我们不分配或克隆数据。相反,我们从发布者的内存池中借一个未初始化的样本,填充它,然后以 100 ms 的间隔发送它:
while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
auto sample = publisher.loan_uninit().value();
auto initialized_sample =
sample.write_payload(Distance { get_ultra_sonic_sensor_distance(), 42.0 });
send(std::move(initialized_sample)).value();
} 创建订阅者
创建订阅者与发布者类似:
#include "iox2/iceoryx2.hpp"
using namespace iox2;
auto node = NodeBuilder().create<ServiceType::Ipc>().value();
auto service = node.service_builder(ServiceName::create("distance_to_obstacle").value())
.publish_subscribe<Distance>()
.open_or_create()
.value();
auto subscriber = service.subscriber_builder().create().value();
while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
auto sample = subscriber.receive().value();
while (sample.has_value()) {
std::cout << "received distance: " << sample->payload() << std::endl;
sample = subscriber.receive().value();
}
} 小结
上手路径一共四步:NodeBuilder 建节点(进程内通信用 ServiceType::Ipc)→ 定义共享内存兼容的负载结构体 → service_builder(...).publish_subscribe<T>().open_or_create() 建服务 → publisher_builder() / subscriber_builder() 创建收发两端。发布侧的核心是 loan_uninit() 借样本、write_payload() 填充后发送的零拷贝流程,这也是 pub-sub 模型无论负载大小都能保持基本恒定延迟的原因。
译注:发布循环中的 send(std::move(initialized_sample)).value(); 来自官方示例的辅助封装,完整可编译代码见 iceoryx2 仓库的 examples/cxx/publish_subscribe 目录。本站相关文章:iceoryx2 黑板机制:共享内存配置分发、iceoryx2 动态类型:Slice 动态 payload 与多段扩容。